﻿
using System;
using System.Collections.Generic;
using System.Text;

namespace SharpSoft.Geometries.Shapes
{
    public class Transform2D
    {
        Matrix3x3 matrix;
        public Transform2D()
        {
            matrix = new Matrix3x3(); 
        }

        public Transform2D(Matrix3x3 m)
        {
            matrix = m;
        }
        /// <summary>
        /// 计算逆矩阵
        /// </summary>
        /// <returns></returns>
        public Transform2D Invert()
        {
            return new Transform2D(new Matrix3x3(matrix.Invert()));
        }


        #region 计算
        public Vector2D Transform(Vector2D vector)
        {
            double x = vector.X, y = vector.Y;
            MultiplyVector(ref x, ref y);
            return new Vector2D(x, y);
        }
        public Vector2D[] Transform(Vector2D[] vectors)
        {
            Vector2D[] ds = new Vector2D[vectors.Length];
            for (int i = 0; i < vectors.Length; i++)
            {
                double x = vectors[i].X, y = vectors[i].Y;
                MultiplyVector(ref x, ref y);
                ds[i] = new Vector2D(x, y);
            }
            return ds;
        }

        internal void MultiplyVector(ref double x, ref double y)
        {

            double num = y * matrix.M21;
            double num2 = x * matrix.M12;
            x *= matrix.M11;
            x += num;
            y *= matrix.M22;
            y += num2;
        }

        public Point2D Transform(Point2D point)
        {
            double x = point.X, y = point.Y;
            MultiplyPoint(ref x, ref y);
            return new Point2D(x, y);
        }
        public Point2D[] Transform(Point2D[] points)
        {
            var ps = new Point2D[points.Length];
            for (int i = 0; i < ps.Length; i++)
            {
                double x = points[i].X, y = points[i].Y;
                MultiplyPoint(ref x, ref y);
                ps[i] = new Point2D(x, y);
            }
            return ps;
        }
        internal void MultiplyPoint(ref double x, ref double y)
        {
            //switch (_type)
            //{
            //    case MatrixTypes.TRANSFORM_IS_IDENTITY:
            //        break;
            //    case MatrixTypes.TRANSFORM_IS_TRANSLATION:
            //        x += _offsetX;
            //        y += _offsetY;
            //        break;
            //    case MatrixTypes.TRANSFORM_IS_SCALING:
            //        x *= _m11;
            //        y *= _m22;
            //        break;
            //    case MatrixTypes.TRANSFORM_IS_TRANSLATION | MatrixTypes.TRANSFORM_IS_SCALING:
            //        x *= _m11;
            //        x += _offsetX;
            //        y *= _m22;
            //        y += _offsetY;
            //        break;
            //    default:
            //        { 

            double num = y * matrix.M21 + matrix.OffsetX;
            double num2 = x * matrix.M12 + matrix.OffsetY;
            x *= matrix.M11;
            x += num;
            y *= matrix.M22;
            y += num2;
            //break;
            //        }
            //}
        }
        #endregion

        #region 变换
        /// <summary>
        /// 缩放
        /// </summary>
        /// <param name="scaleX"></param>
        /// <param name="scaleY"></param>
        /// <param name="centerX"></param>
        /// <param name="centerY"></param>
        public void ScaleAt(double scaleX, double scaleY, double centerX, double centerY)
        {
            matrix = new Matrix3x3(matrix * CreateScaling(scaleX, scaleY, centerX, centerY));
        }
        /// <summary>
        /// 旋转
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="centerX"></param>
        /// <param name="centerY"></param>
        public void RotationAt(Radian angle, double centerX, double centerY)
        {
            matrix *= CreateRotationRadians((double)angle, centerX, centerY);
        }
        /// <summary>
        /// 平移
        /// </summary>
        /// <param name="offsetX"></param>
        /// <param name="offsetY"></param>
        public void Translate(double offsetX, double offsetY)
        {
            //OffsetX += offsetX;
            //OffsetY += offsetY;
            matrix *= CreateTranslation(offsetX, offsetY);
        }
        /// <summary>
        /// 平移
        /// </summary> 
        public void Translate(Vector2D vector)
        {
            Translate(vector.X, vector.Y);
        }
        /// <summary>
        /// 倾斜
        /// </summary>
        /// <param name="skewX"></param>
        /// <param name="skewY"></param>
        public void Skew(Radian skewX, Radian skewY)
        {
            matrix *= CreateSkewRadians((double)skewX, (double)skewY);
        }
        #endregion

        #region internal

        internal static Matrix3x3 CreateScaling(double scaleX, double scaleY)
        {
            Matrix3x3 result = new Matrix3x3();
            result.SetMatrix(scaleX, 0.0, 0.0, scaleY, 0.0, 0.0);
            return result;
        }
        internal static Matrix3x3 CreateScaling(double scaleX, double scaleY, double centerX, double centerY)
        {
            Matrix3x3 result = new Matrix3x3();
            result.SetMatrix(scaleX, 0.0, 0.0, scaleY, centerX - scaleX * centerX, centerY - scaleY * centerY);
            return result;
        }
        internal static Matrix3x3 CreateSkewRadians(double skewX, double skewY)
        {
            Matrix3x3 result = new Matrix3x3();
            result.SetMatrix(1.0, Math.Tan(skewY), Math.Tan(skewX), 1.0, 0.0, 0.0);
            return result;
        }
        internal static Matrix3x3 CreateRotationRadians(double angle, double centerX, double centerY)
        {
            Matrix3x3 result = new Matrix3x3();
            double num = Math.Sin(angle);
            double num2 = Math.Cos(angle);
            double offsetX = centerX * (1.0 - num2) + centerY * num;
            double offsetY = centerY * (1.0 - num2) - centerX * num;
            result.SetMatrix(num2, num, 0.0 - num, num2, offsetX, offsetY);
            return result;
        }
        internal static Matrix3x3 CreateTranslation(double offsetX, double offsetY)
        {
            Matrix3x3 result = new Matrix3x3();
            result.SetMatrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY);
            return result;
        }

        #endregion
    }
}
